Az R Notebookról bővebben
Töltsünk be egy pár csomagot!
Miről szól a felfedező adatelemzés?
Az a cél, hogy elkezdjük érteni az adatokat.
Kreatív folyamat, hagyatkozzunk a megérzéseinkre (is),
- Találj ki kérdéseket az adatokkal kapcsolatban!
- Próbáld megválaszolni őket ábrázolások, transzformációk, és modellek által!
- Ezek fényében finomítsd a kérdéseket, és tegyél fel újakat!
Érdemes jó sok kérdéssel indítani, aztán majd elválik, hogy melyikkel mennyit érdemes foglalkozni
Nincsenek szigorúan értelmezett szabályok, két kérdés viszont általában érdekes:
- milyen a változók variabilitása?
- milyen a változók közös varianciája?
Változók variabilitásának vizsgálata
Eloszlások megjelenítése
Kategorikus változók: oszlopdiagram 
Oszlopok magassága
x lehetséges értékeinek darabszámát mutatja
Folytonos változók eloszlását pedig megnézhetjük mondjuk egy hisztogramon 
A megjelenített értékek kiszámolása
geom_histogram binwidth argumentuma mondja meg, hogy az x változót mekkora intervallumokra szabdaljuk fel az ábrázoláshoz - érdemes kipróbálni több értéket! Pl. csak a három karátnál kisebb gyémántok, keskenyebb binekkel:

Ugyanez szétdobva csiszolás szerint fazettákra 
Ha több kategória eloszlását egy ábrán akarjuk mutatni, rajzoljunk inkább vonalakat! 
Mire érdemes figyelni?
- Mik a leggyakoribb értékek? Miért?
- Mik a legritkább értékek? Miért? Erre számítottunk?
- Szokatlan, különös mintázatok? Mi lehet az oka?
Mi az érdekes ezen az ábrán? 
És ezen? 
Klaszterekbe tömörülő hasonló értékek alcsoportokra utalhatnak.
- Milyen szempontból hasonlóak egymáshoz az egy csoportba tartozó megfigyelések?
- Milyen szempontból különböznek egymástól a külön csoportokba tartozó megfigyelések?
- Hogyan lehetne jellemezni a klasztereket?
- Miért lehet félrevezető a klaszterek jelenléte?
Szokatlan értékek (outlier)
Több oka is lehet!
- adatrögzítési hiba
- ritkán előforduló eset, amit informatív lehet

Hol van itt az outlier? Közelítsünk rá az ábrára!

Nézzük meg jobban ezeket a megfigyeléseket!
Gondoljuk végig alaposan: mi okozhatta ezeket az anomáliákat?
Gyakorlás - eloszlások ábrázolása
Vizsgáld meg a price változó eloszlását! Észreveszel-e valami furát?
Hiányzó értékek
Mit tegyünk ezekkel a furcsa gyémántokkal?
## Warning: Removed 9 rows containing missing values (geom_point).

ggplot2 figyelmeztet az NA-kra
De az is lehet, hogy pont a hiányzó értékeket tartalmazó megfigyelések érdekesek Pl. mikor kellett volna indulniuk a törölt járatoknak?

Miért nem túl informatív ez az ábra?
Változók közös varianciája
Kategorikus vs. folytonos

A gyakoriságokban nagy eltérések vannak, ezért nem látszik jól, hogy különbözik-e a különböző csiszolású gyémántok eloszlása

Ilyenkor darabszám helyett érdemes a sűrűséget mutatni: 
Vagy használhatunk boxplotot is 
A rosszabb minőségű gyémántok drágábbak lennének?
A csiszolás szempontjából egyértelműen rangsorolhatóak a gyémántok. De nem minden kategorikus változó ordinális. Vegyük például a különböző típusú autók fogyasztását.

Az ábra áttekinthetőbb lehet, ha a fogyasztás mediánja szerint sorbarendezzük a kategóriákat

Ha hosszúak a változónevek, forgassunk egyet az ábrán: 
Gyakorlás - kovariancia ábrázolása 1.
Hogyan javíthatnánk akkor ezen az ábrán az eddigiek fényében? 
Kategorikus vs. kategorikus

Az ábrához tartozó gyakorisági tábla
Amit megmutathatunk egy szép hőtérképen is 
Gyakorlás - kovariancia ábrázolása 2.
A dplyr és a geom_tile() felhasználásával nézzük meg, hogyan alakul az átlagos késés célállomásonként, havi bontásban. Miért lehet nehézkes ez az ábra? Mit lehetne kezdeni vele?
Folytonos vs. folytonos

Hátha többet látunk, ha áttetszővé tesszük a pontokat 
Nagy adathalmazokon nem mindig segít az áttetszőség szabályzása Ilyenkor binekre is oszthatjuk az adatokat 
Készíthetünk boxplotot is, ha csak az egyik folytonos változót szeleteljük: 
Ebből nem derül ki, hogy melyik dobozban hány gyémánt van, nézzük meg! 
Vagy daraboljunk körülbelül egyforma elemszámú bin-ekre! 
Gyakorlás - kovariancia ábrázolása 3.
Ábrázoljuk az eddigiek segítségével a csiszolás, a karát, és az ár kombinált eloszlását!
Összetett felfedező elemzések gyorsan
GGally
Változók eloszlása és kapcsolata egy nagy ábrán, egyetlen sor kóddal 
Érdemes tudni a base graphics pairs() függvényéről is: kevésbé látványos, viszont jóval gyorsabb 
Egyéb pontfelhő-mátrix lehetőségek
Hasznos lehet még a ggcoef() egy modell együtthatóinak gyors áttekintéséhez
Nézzünk egy példát!
Mivel függ össze a fogyasztás? 
Illesszünk többszörös lineáris regresziós modellt, és nézzük meg az eredményeket!
##
## Call:
## lm(formula = mpg ~ ., data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.64562 -0.27212 -0.02854 0.17607 0.97245
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.568e-17 7.740e-02 0.000 1.00000
## disp -1.927e-02 2.128e-01 -0.091 0.92851
## hp -3.544e-01 1.301e-01 -2.724 0.01097 *
## wt -6.171e-01 1.731e-01 -3.565 0.00133 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.4379 on 28 degrees of freedom
## Multiple R-squared: 0.8268, Adjusted R-squared: 0.8083
## F-statistic: 44.57 on 3 and 28 DF, p-value: 8.65e-11
## 2.5 % 97.5 %
## (Intercept) -0.1585520 0.15855201
## disp -0.4552375 0.41670004
## hp -0.6209244 -0.08795267
## wt -0.9716283 -0.26249869
Mindezt ábrázolhatjuk is 
corrplot
Korrelációs mátrixok ábrázolása 

Akkor igazán hasznos a corrplot, ha sok változó korrelációját szeretnénk egyben áttekinteni.
Például nézzük meg egy 25 kérdésből álló Big Five személyiségteszt tételeinek korrelációit!

További beállítási lehetőségek a corrplot-ban
Interaktív ábrák a plotly-vel
Bevezetés a plotly használatába
Nézzünk meg elsőnek egy vulkánt!
## No trace type specified:
## Based on info supplied, a 'heatmap' trace seems appropriate.
## Read more about this trace type -> https://plot.ly/r/reference/#heatmap
Texas-i ingatlanpiaci adatok
Két út a plotly objektumok létrehozására:
- ggplotly(): egy ggplot objektum átalákítása
- plot_ly(): közvetlenül az adatok megadása
ggplotly(): egy ggplot objektum átalákítása
Készítsünk egy ggplot2 ábrát, ahol az idő függvényében mutatjuk a városonkénti medián eladási árat!
## Warning: Removed 446 rows containing missing values (geom_path).

A tooltip alapból minden információt mutat, amit az esztétikai kapcsolásnál (aes) megadtunk
Felül is írhatjuk, hogy mit kapjon meg a tooltip
plot_ly(): közvetlenül az adatok megadása
Adatok manipulálásra a dplyr és a tidyr függvényeit használhatjuk Pl. a csoportosított adatokat “érti” a plotly (csoportosítás minden egyes szintjére lesz legalább egy grafikai elem)
Létrehozunk egy plotly objektumot
plotly_data() visszaadja egy plotly objektumhoz tartozó adatokat
A plotly csomagban van egy rakás add_*() függvény
Ezek öröklik a plot_ly() híváskor meghatározott attribútumokat (pl. melyik tengelyen mi legyen)
És öröklik a plotly objektumhoz tartozó adatokat, amit felülírhatunk a data argumentumnál
Gondolhatunk úgy is ezekre a függvényekre mint a ggplot2 rétegeinek egy változatára
LS0tDQp0aXRsZTogIkZlbGZlZGV6xZEgYWRhdGVsZW16w6lzIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6DQogICAgICB0b2NfY29sbGFwc2VkOiB0cnVlDQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCi0tLQ0KDQpbQXogUiBOb3RlYm9va3LDs2wgYsWRdmViYmVuXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vbm90ZWJvb2suaHRtbCkNCg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCiMgZXp6ZWwgYSBzb3JyYWwgw6FsbMOtdGhhdG7DoW5rIGJlLCBob2d5IGEga8OzZCBuZSBrZXLDvGxqw7ZuIGJlbGUgYSBrbml0dGVsdCBkb2tzaWJhDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobz1GQUxTRSkNCmBgYA0KDQpUw7ZsdHPDvG5rIGJlIGVneSBww6FyIGNzb21hZ290IQ0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShodG1sd2lkZ2V0cykNCmxpYnJhcnkoR0dhbGx5KQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KGNvcnJwbG90KQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGh0bWx3aWRnZXRzKQ0KYGBgDQoNCg0KI01pcsWRbCBzesOzbCBhIGZlbGZlZGV6xZEgYWRhdGVsZW16w6lzPw0KDQpBeiBhIGPDqWwsIGhvZ3kgZWxrZXpkasO8ayDDqXJ0ZW5pIGF6IGFkYXRva2F0Lg0KDQpLcmVhdMOtdiBmb2x5YW1hdCwgaGFneWF0a296enVuayBhIG1lZ8OpcnrDqXNlaW5rcmUgKGlzKSwgICANCg0KMS4gVGFsw6FsaiBraSBrw6lyZMOpc2VrZXQgYXogYWRhdG9ra2FsIGthcGNzb2xhdGJhbiENCjIuIFByw7Niw6FsZCBtZWd2w6FsYXN6b2xuaSDFkWtldCDDoWJyw6F6b2zDoXNvaywgdHJhbnN6Zm9ybcOhY2nDs2ssIMOpcyBtb2RlbGxlayDDoWx0YWwhDQozLiBFemVrIGbDqW55w6liZW4gZmlub23DrXRzZCBhIGvDqXJkw6lzZWtldCwgw6lzIHRlZ3nDqWwgZmVsIMO6amFrYXQhDQoNCsOJcmRlbWVzIGrDsyBzb2sga8OpcmTDqXNzZWwgaW5kw610YW5pLCBhenTDoW4gbWFqZCBlbHbDoWxpaywgDQpob2d5IG1lbHlpa2tlbCBtZW5ueWl0IMOpcmRlbWVzIGZvZ2xhbGtvem5pDQoNCk5pbmNzZW5layBzemlnb3LDumFuIMOpcnRlbG1lemV0dCBzemFiw6FseW9rLCBrw6l0IGvDqXJkw6lzIHZpc3pvbnQgw6FsdGFsw6FiYW4gw6lyZGVrZXM6IA0KDQotIG1pbHllbiBhIHbDoWx0b3rDs2sgdmFyaWFiaWxpdMOhc2E/DQotIG1pbHllbiBhIHbDoWx0b3rDs2sga8O2esO2cyB2YXJpYW5jacOhamE/DQoNCiMjVsOhbHRvesOzayB2YXJpYWJpbGl0w6Fzw6FuYWsgdml6c2fDoWxhdGEgDQogDQpFbG9zemzDoXNvayBtZWdqZWxlbsOtdMOpc2UNCiANCg0KS2F0ZWdvcmlrdXMgdsOhbHRvesOzazogb3N6bG9wZGlhZ3JhbQ0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArDQogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCkpDQpgYGANCg0KT3N6bG9wb2sgbWFnYXNzw6FnYSAqeCogbGVoZXRzw6lnZXMgw6lydMOpa2VpbmVrIGRhcmFic3rDoW3DoXQgbXV0YXRqYQ0KYGBge3J9DQpkaWFtb25kcyAlPiUgDQogIGNvdW50KGN1dCkNCmBgYA0KDQoNCkZvbHl0b25vcyB2w6FsdG96w7NrIGVsb3N6bMOhc8OhdCBwZWRpZyBtZWduw6l6aGV0asO8ayBtb25kanVrIGVneSBoaXN6dG9ncmFtb24NCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKw0KICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHggPSBjYXJhdCksIGJpbndpZHRoID0gMC41KQ0KYGBgDQoNCg0KQSBtZWdqZWxlbsOtdGV0dCDDqXJ0w6lrZWsga2lzesOhbW9sw6FzYQ0KDQpgYGB7cn0NCmRpYW1vbmRzICU+JSANCiAgY291bnQoY3V0X3dpZHRoKGNhcmF0LCAwLjUpKQ0KYGBgDQoNCmdlb21faGlzdG9ncmFtIGJpbndpZHRoIGFyZ3VtZW50dW1hIG1vbmRqYSBtZWcsIA0KaG9neSBheiB4IHbDoWx0b3rDs3QgbWVra29yYSBpbnRlcnZhbGx1bW9rcmEgc3phYmRhbGp1ayBmZWwNCmF6IMOhYnLDoXpvbMOhc2hveiAtIMOpcmRlbWVzIGtpcHLDs2LDoWxuaSB0w7ZiYiDDqXJ0w6lrZXQhDQpQbC4gY3NhayBhIGjDoXJvbSBrYXLDoXRuw6FsIGtpc2ViYiBnecOpbcOhbnRvaywga2Vza2VueWViYiBiaW5la2tlbDoNCg0KYGBge3J9DQpzbWFsbGVyIDwtIGRpYW1vbmRzICU+JSANCiAgZmlsdGVyKGNhcmF0IDwgMykNCg0KZ2dwbG90KGRhdGEgPSBzbWFsbGVyLCBtYXBwaW5nID0gYWVzKHggPSBjYXJhdCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjEpIA0KDQpgYGANCg0KDQpVZ3lhbmV6IHN6w6l0ZG9idmEgY3Npc3pvbMOhcyBzemVyaW50IGZhemV0dMOha3JhDQpgYGB7ciwgZmlnLmhlaWdodD02fQ0KZ2dwbG90KGRhdGEgPSBzbWFsbGVyLCBtYXBwaW5nID0gYWVzKHggPSBjYXJhdCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjEpICsgDQogIGZhY2V0X3dyYXAofiBjdXQsIG5yb3cgPSA1KQ0KYGBgDQoNCg0KDQpIYSB0w7ZiYiBrYXRlZ8OzcmlhIGVsb3N6bMOhc8OhdCBlZ3kgw6FicsOhbiBha2FyanVrIG11dGF0bmksIHJhanpvbGp1bmsgaW5rw6FiYiB2b25hbGFrYXQhDQpgYGB7cn0NCmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIGNvbG91ciA9IGN1dCkpICsNCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDAuMSwgc2l6ZSA9IDIpDQpgYGANCg0KDQpNaXJlIMOpcmRlbWVzIGZpZ3llbG5pPw0KDQotIE1payBhIGxlZ2d5YWtvcmliYiDDqXJ0w6lrZWs/IE1pw6lydD8gDQotIE1payBhIGxlZ3JpdGvDoWJiIMOpcnTDqWtlaz8gTWnDqXJ0PyBFcnJlIHN6w6Ftw610b3R0dW5rPw0KLSBTem9rYXRsYW4sIGvDvGzDtm7DtnMgbWludMOhemF0b2s/IE1pIGxlaGV0IGF6IG9rYT8NCg0KDQpNaSBheiDDqXJkZWtlcyBlemVuIGF6IMOhYnLDoW4/DQpgYGB7cn0NCmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4wMSkNCmBgYA0KDQoNCg0Kw4lzIGV6ZW4/DQpgYGB7cn0NCmdncGxvdChkYXRhID0gZmFpdGhmdWwsIG1hcHBpbmcgPSBhZXMoeCA9IGVydXB0aW9ucykpICsgDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4yNSkgKyANCiAgeGxhYigiS2l0w7Zyw6lzIGhvc3N6YSAocGVyYykiKSArDQogIHlsYWIoIkd5YWtvcmlzw6FnIikgKyANCiAgZ2d0aXRsZSgiQXogT2xkIEZhaXRoZnVsIGdlanrDrXIga2l0w7Zyw6lzZWkiKQ0KYGBgDQoNCktsYXN6dGVyZWtiZSB0w7Ztw7Zyw7xsxZEgaGFzb25sw7Mgw6lydMOpa2VrIGFsY3NvcG9ydG9rcmEgdXRhbGhhdG5hay4NCg0KLSBNaWx5ZW4gc3plbXBvbnRiw7NsIGhhc29ubMOzYWsgZWd5bcOhc2hveiBheiBlZ3kgY3NvcG9ydGJhIHRhcnRvesOzIG1lZ2ZpZ3llbMOpc2VrPw0KLSBNaWx5ZW4gc3plbXBvbnRiw7NsIGvDvGzDtm5iw7Z6bmVrIGVneW3DoXN0w7NsIGEga8O8bMO2biBjc29wb3J0b2tiYSB0YXJ0b3rDsyBtZWdmaWd5ZWzDqXNlaz8gDQotIEhvZ3lhbiBsZWhldG5lIGplbGxlbWV6bmkgYSBrbGFzenRlcmVrZXQ/DQotIE1pw6lydCBsZWhldCBmw6lscmV2ZXpldMWRIGEga2xhc3p0ZXJlayBqZWxlbmzDqXRlPyANCg0KDQpTem9rYXRsYW4gw6lydMOpa2VrIChvdXRsaWVyKQ0KDQpUw7ZiYiBva2EgaXMgbGVoZXQhIA0KDQotIGFkYXRyw7ZnesOtdMOpc2kgaGliYQ0KLSByaXRrw6FuIGVsxZFmb3JkdWzDsyBlc2V0LCBhbWl0IGluZm9ybWF0w612IGxlaGV0DQoNCmBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzKSArIA0KICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHggPSB5KSwgYmlud2lkdGggPSAwLjUpDQpgYGANCg0KSG9sIHZhbiBpdHQgYXogb3V0bGllcj8gS8O2emVsw610c8O8bmsgcsOhIGF6IMOhYnLDoXJhIQ0KDQpgYGB7cn0NCmdncGxvdChkaWFtb25kcykgKyANCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4ID0geSksIGJpbndpZHRoID0gMC41KSArDQogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCA1MCkpDQpgYGANCg0KDQpOw6l6esO8ayBtZWcgam9iYmFuIGV6ZWtldCBhIG1lZ2ZpZ3llbMOpc2VrZXQhDQpgYGB7cn0NCih1bnVzdWFsIDwtIGRpYW1vbmRzICU+JSANCiAgZmlsdGVyKHkgPCAzIHwgeSA+IDIwKSAlPiUgDQogIHNlbGVjdChwcmljZSwgeCwgeSwgeikgJT4lDQogIGFycmFuZ2UoeSkpDQpgYGANCg0KR29uZG9sanVrIHbDqWdpZyBhbGFwb3NhbjogbWkgb2tvemhhdHRhIGV6ZWtldCBheiBhbm9tw6FsacOha2F0Pw0KDQoNCiMjI0d5YWtvcmzDoXMgLSBlbG9zemzDoXNvayDDoWJyw6F6b2zDoXNhDQoNClZpenNnw6FsZCBtZWcgYSBwcmljZSB2w6FsdG96w7MgZWxvc3psw6Fzw6F0ISDDiXN6cmV2ZXN6ZWwtZSB2YWxhbWkgZnVyw6F0Pw0KDQoNCg0KIyNIacOhbnl6w7Mgw6lydMOpa2VrIA0KDQpNaXQgdGVnecO8bmsgZXpla2tlbCBhIGZ1cmNzYSBnecOpbcOhbnRva2thbD8NCg0KLSBlbGRvYmhhdGp1ayDFkWtldCAtIG1pw6lydCBuZW0gc3plcmVuY3PDqXM/DQoNCmBgYHtyfQ0KZGlhbW9uZHMyIDwtIGRpYW1vbmRzICU+JSANCiAgZmlsdGVyKGJldHdlZW4oeSwgMywgMjApKQ0KYGBgDQoNCg0KDQotICBhIGZ1cmNzYSDDqXJ0w6lrZWlrZXQgw6F0w61yanVrIGhpw6FueXrDs3JhDQoNCg0KYGBge3J9DQpkaWFtb25kczIgPC0gZGlhbW9uZHMgJT4lIA0KICBtdXRhdGUoeSA9IGlmZWxzZSh5IDwgMyB8IHkgPiAyMCwgTkEsIHkpKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gZGlhbW9uZHMyLCBtYXBwaW5nID0gYWVzKHggPSB4LCB5ID0geSkpICsgDQogIGdlb21fcG9pbnQoKQ0KYGBgDQoNCg0KDQpnZ3Bsb3QyIGZpZ3llbG1lenRldCBheiBOQS1rcmENCg0KRGUgYXogaXMgbGVoZXQsIGhvZ3kgcG9udCBhIGhpw6FueXrDsyDDqXJ0w6lrZWtldCB0YXJ0YWxtYXrDsyBtZWdmaWd5ZWzDqXNlayDDqXJkZWtlc2VrIA0KUGwuIG1pa29yIGtlbGxldHQgdm9sbmEgaW5kdWxuaXVrIGEgdMO2csO2bHQgasOhcmF0b2tuYWs/IA0KDQoNCmBgYHtyfQ0KbnljZmxpZ2h0czEzOjpmbGlnaHRzICU+JSANCiAgbXV0YXRlKA0KICAgIGNhbmNlbGxlZCA9IGlzLm5hKGRlcF90aW1lKSwNCiAgICBzY2hlZF9ob3VyID0gc2NoZWRfZGVwX3RpbWUgJS8lIDEwMCwNCiAgICBzY2hlZF9taW4gPSBzY2hlZF9kZXBfdGltZSAlJSAxMDAsDQogICAgc2NoZWRfZGVwX3RpbWUgPSBzY2hlZF9ob3VyICsgc2NoZWRfbWluIC8gNjANCiAgKSAlPiUgDQogIGdncGxvdChtYXBwaW5nID0gYWVzKHNjaGVkX2RlcF90aW1lKSkgKyANCiAgZ2VvbV9mcmVxcG9seShtYXBwaW5nID0gYWVzKGNvbG91ciA9IGNhbmNlbGxlZCksIGJpbndpZHRoID0gMS80KQ0KDQpgYGANCg0KDQpNacOpcnQgbmVtIHTDumwgaW5mb3JtYXTDrXYgZXogYXogw6FicmE/IA0KDQoNCiMjIFbDoWx0b3rDs2sga8O2esO2cyB2YXJpYW5jacOhamEgDQoNCg0KIyMjS2F0ZWdvcmlrdXMgdnMuIGZvbHl0b25vcw0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gZGlhbW9uZHMsIG1hcHBpbmcgPSBhZXMoeCA9IHByaWNlKSkgKyANCiAgZ2VvbV9mcmVxcG9seShtYXBwaW5nID0gYWVzKGNvbG91ciA9IGN1dCksIGJpbndpZHRoID0gNTAwKQ0KYGBgDQoNCkEgZ3lha29yaXPDoWdva2JhbiBuYWd5IGVsdMOpcsOpc2VrIHZhbm5haywgZXrDqXJ0IG5lbSBsw6F0c3ppayBqw7NsLCBob2d5IGvDvGzDtm5iw7Z6aWstZQ0KYSBrw7xsw7ZuYsO2esWRIGNzaXN6b2zDoXPDuiBnecOpbcOhbnRvayBlbG9zemzDoXNhDQoNCmBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzKSArIA0KICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQpKQ0KYGBgDQoNCg0KSWx5ZW5rb3IgZGFyYWJzesOhbSBoZWx5ZXR0IMOpcmRlbWVzIGEgc8WxcsWxc8OpZ2V0IG11dGF0bmk6DQpgYGB7cn0NCmdncGxvdChkYXRhID0gZGlhbW9uZHMsIG1hcHBpbmcgPSBhZXMoeCA9IHByaWNlLCB5ID0gLi5kZW5zaXR5Li4pKSArIA0KICBnZW9tX2ZyZXFwb2x5KG1hcHBpbmcgPSBhZXMoY29sb3VyID0gY3V0KSwgYmlud2lkdGggPSA1MDApDQpgYGANCg0KDQpWYWd5IGhhc3puw6FsaGF0dW5rIGJveHBsb3RvdCBpcw0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzLCBtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBwcmljZSkpICsNCiAgZ2VvbV9ib3hwbG90KCkNCmBgYA0KDQpBIHJvc3N6YWJiIG1pbsWRc8OpZ8WxIGd5w6ltw6FudG9rIGRyw6Fnw6FiYmFrIGxlbm7DqW5laz8NCg0KDQpBIGNzaXN6b2zDoXMgc3plbXBvbnRqw6Fiw7NsIGVnecOpcnRlbG3FsWVuIHJhbmdzb3JvbGhhdMOzYWsgYSBnecOpbcOhbnRvay4NCkRlIG5lbSBtaW5kZW4ga2F0ZWdvcmlrdXMgdsOhbHRvesOzIG9yZGluw6FsaXMuDQpWZWd5w7xrIHDDqWxkw6F1bCBhIGvDvGzDtm5iw7Z6xZEgdMOtcHVzw7ogYXV0w7NrIGZvZ3lhc3p0w6Fzw6F0Lg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBjbGFzcywgeSA9IGh3eSkpICsNCiAgZ2VvbV9ib3hwbG90KCkNCmBgYA0KDQpBeiDDoWJyYSDDoXR0ZWtpbnRoZXTFkWJiIGxlaGV0LCBoYSBhIA0KZm9neWFzenTDoXMgbWVkacOhbmphIHN6ZXJpbnQgc29yYmFyZW5kZXp6w7xrIGEga2F0ZWfDs3Jpw6FrYXQNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX2JveHBsb3QobWFwcGluZyA9IGFlcyh4ID0gcmVvcmRlcihjbGFzcywgaHd5LCBGVU4gPSBtZWRpYW4pLCB5ID0gaHd5KSkNCmBgYA0KDQpIYSBob3NzesO6YWsgYSB2w6FsdG96w7NuZXZlaywgZm9yZ2Fzc3VuayBlZ3lldCBheiDDoWJyw6FuOg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKw0KICBnZW9tX2JveHBsb3QobWFwcGluZyA9IGFlcyh4ID0gcmVvcmRlcihjbGFzcywgaHd5LCBGVU4gPSBtZWRpYW4pLCB5ID0gaHd5KSkgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQojIyMjR3lha29ybMOhcyAtIGtvdmFyaWFuY2lhIMOhYnLDoXpvbMOhc2EgMS4NCg0KSG9neWFuIGphdsOtdGhhdG7DoW5rIGFra29yIGV6ZW4gYXogw6FicsOhbiBheiBlZGRpZ2llayBmw6luecOpYmVuPw0KYGBge3J9DQpueWNmbGlnaHRzMTM6OmZsaWdodHMgJT4lIA0KICBtdXRhdGUoDQogICAgY2FuY2VsbGVkID0gaXMubmEoZGVwX3RpbWUpLA0KICAgIHNjaGVkX2hvdXIgPSBzY2hlZF9kZXBfdGltZSAlLyUgMTAwLA0KICAgIHNjaGVkX21pbiA9IHNjaGVkX2RlcF90aW1lICUlIDEwMCwNCiAgICBzY2hlZF9kZXBfdGltZSA9IHNjaGVkX2hvdXIgKyBzY2hlZF9taW4gLyA2MA0KICApICU+JSANCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoc2NoZWRfZGVwX3RpbWUpKSArIA0KICBnZW9tX2ZyZXFwb2x5KG1hcHBpbmcgPSBhZXMoY29sb3VyID0gY2FuY2VsbGVkKSwgYmlud2lkdGggPSAxLzQpDQoNCmBgYA0KDQoNCiMjI0thdGVnb3Jpa3VzIHZzLiBrYXRlZ29yaWt1cw0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArDQogIGdlb21fY291bnQobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gY29sb3IpKQ0KYGBgDQoNCkF6IMOhYnLDoWhveiB0YXJ0b3rDsyBneWFrb3Jpc8OhZ2kgdMOhYmxhDQpgYGB7cn0NCmRpYW1vbmRzICU+JSANCiAgY291bnQoY29sb3IsIGN1dCkgDQpgYGANCg0KQW1pdCBtZWdtdXRhdGhhdHVuayBlZ3kgc3rDqXAgaMWRdMOpcmvDqXBlbiBpcw0KYGBge3J9DQpkaWFtb25kcyAlPiUgDQogIGNvdW50KGNvbG9yLCBjdXQpICU+JSAgDQogIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBjb2xvciwgeSA9IGN1dCkpICsNCiAgZ2VvbV90aWxlKG1hcHBpbmcgPSBhZXMoZmlsbCA9IG4pKQ0KYGBgDQoNCiMjIyNHeWFrb3Jsw6FzIC0ga292YXJpYW5jaWEgw6FicsOhem9sw6FzYSAyLg0KDQoNCkEgZHBseXIgw6lzIGEgZ2VvbV90aWxlKCkgZmVsaGFzem7DoWzDoXPDoXZhbCBuw6l6esO8ayBtZWcsIGhvZ3lhbiBhbGFrdWwgYXogw6F0bGFnb3Mga8Opc8Opcw0KY8OpbMOhbGxvbcOhc29ua8OpbnQsIGhhdmkgYm9udMOhc2Jhbi4gDQpNacOpcnQgbGVoZXQgbmVow6l6a2VzIGV6IGF6IMOhYnJhPyBNaXQgbGVoZXRuZSBrZXpkZW5pIHZlbGU/DQoNCg0KDQoNCiMjI0ZvbHl0b25vcyB2cy4gZm9seXRvbm9zDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKQ0KYGBgDQoNCkjDoXRoYSB0w7ZiYmV0IGzDoXR1bmssIGhhIMOhdHRldHN6xZF2w6kgdGVzc3rDvGsgYSBwb250b2thdA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpLCBhbHBoYSA9IDEgLyAxMDApDQpgYGANCg0KTmFneSBhZGF0aGFsbWF6b2tvbiBuZW0gbWluZGlnIHNlZ8OtdCBheiDDoXR0ZXRzesWRc8OpZyBzemFiw6FseXrDoXNhDQpJbHllbmtvciBiaW5la3JlIGlzIG9zenRoYXRqdWsgYXogYWRhdG9rYXQNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBzbWFsbGVyKSArDQogIGdlb21fYmluMmQobWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSksIGJpbnMgPSAzMCkNCmBgYA0KDQpLw6lzesOtdGhldMO8bmsgYm94cGxvdG90IGlzLCBoYSBjc2FrIGF6IGVneWlrIGZvbHl0b25vcyB2w6FsdG96w7N0IHN6ZWxldGVsasO8azoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBzbWFsbGVyLCBtYXBwaW5nID0gYWVzKHggPSBjYXJhdCwgeSA9IHByaWNlKSkgKyANCiAgZ2VvbV9ib3hwbG90KG1hcHBpbmcgPSBhZXMoZ3JvdXAgPSBjdXRfd2lkdGgoY2FyYXQsIDAuMSkpKQ0KYGBgDQoNCkViYsWRbCBuZW0gZGVyw7xsIGtpLCBob2d5IG1lbHlpayBkb2JvemJhbiBow6FueSBnecOpbcOhbnQgdmFuLCBuw6l6esO8ayBtZWchDQpgYGB7cn0NCmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsgDQogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKGdyb3VwID0gY3V0X3dpZHRoKGNhcmF0LCAwLjEpKSwgdmFyd2lkdGggPSBUUlVFKQ0KDQpgYGANCg0KDQpWYWd5IGRhcmFib2xqdW5rIGvDtnLDvGxiZWzDvGwgZWd5Zm9ybWEgZWxlbXN6w6Ftw7ogYmluLWVrcmUhDQpgYGB7cn0NCmdncGxvdChkYXRhID0gc21hbGxlciwgbWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsgDQogIGdlb21fYm94cGxvdChtYXBwaW5nID0gYWVzKGdyb3VwID0gY3V0X251bWJlcihjYXJhdCwgMjApKSkNCmBgYA0KDQojIyMjR3lha29ybMOhcyAtIGtvdmFyaWFuY2lhIMOhYnLDoXpvbMOhc2EgMy4NCg0Kw4FicsOhem9sanVrIGF6IGVkZGlnaWVrIHNlZ8OtdHPDqWfDqXZlbCBhIGNzaXN6b2zDoXMsIGEga2Fyw6F0LCDDqXMgYXogw6FyIGtvbWJpbsOhbHQgZWxvc3psw6Fzw6F0IQ0KDQoNCg0KI8OWc3N6ZXRldHQgZmVsZmVkZXrFkSBlbGVtesOpc2VrIGd5b3JzYW4NCg0KIyNHR2FsbHkgDQoNClbDoWx0b3rDs2sgZWxvc3psw6FzYSDDqXMga2FwY3NvbGF0YSBlZ3kgbmFneSDDoWJyw6FuLCBlZ3lldGxlbiBzb3Iga8OzZGRhbA0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRX0NCmdncGFpcnMoaXJpcywgcHJvZ3Jlc3M9RkFMU0UpDQpgYGANCg0Kw4lyZGVtZXMgdHVkbmkgYSBiYXNlIGdyYXBoaWNzIHBhaXJzKCkgZsO8Z2d2w6luecOpcsWRbCBpczoga2V2w6lzYsOpIGzDoXR2w6FueW9zLCB2aXN6b250IGrDs3ZhbCBneW9yc2FiYg0KYGBge3IsIGZpZy5oZWlnaHQ9NywgIGZpZy53aWR0aD03fQ0KcGFpcnMoaXJpcywgcGNoPTE2KQ0KYGBgDQoNCltFZ3nDqWIgcG9udGZlbGjFkS1tw6F0cml4IGxlaGV0xZFzw6lnZWtdKGh0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvd2lraS9zY2F0dGVyLXBsb3QtbWF0cmljZXMtci1iYXNlLWdyYXBocyNyLWJhc2Utc2NhdHRlci1wbG90LW1hdHJpY2VzLXBhaXJzKQ0KDQpIYXN6bm9zIGxlaGV0IG3DqWcgYSBnZ2NvZWYoKSBlZ3kgbW9kZWxsIGVnecO8dHRoYXTDs2luYWsgZ3lvcnMgw6F0dGVraW50w6lzw6loZXoNCg0KTsOpenrDvG5rIGVneSBww6lsZMOhdCENCg0KTWl2ZWwgZsO8Z2cgw7Zzc3plIGEgZm9neWFzenTDoXM/IA0KYGBge3J9DQptdGNhcnMgJT4lIA0KICBzZWxlY3QobXBnLCBkaXNwLCBocCwgd3QpICU+JSANCiAgcGFpcnMoKQ0KYGBgDQoNCklsbGVzc3rDvG5rIHTDtmJic3rDtnLDtnMgbGluZcOhcmlzIHJlZ3Jlc3ppw7NzIG1vZGVsbHQsIMOpcyBuw6l6esO8ayBtZWcgYXogZXJlZG3DqW55ZWtldCENCmBgYHtyfQ0KbW9kZWwgPC0gDQogIG10Y2FycyAlPiUgDQogIHNlbGVjdChtcGcsIGRpc3AsIGhwLCB3dCkgJT4lIA0KICAjIHN0YW5kYXJkaXrDoWxqdWsgYSB2w6FsdG96w7NrYXQsIGhvZ3kgc3RhbmRhcmRpesOhbHQgZWd5w7x0dGhhdMOza2F0IGthcGp1bmsNCiAgbXV0YXRlX2FsbChzY2FsZSkgJT4lDQogIGxtKG1wZyB+ICAuLCBkYXRhID0gLikNCg0Kc3VtbWFyeShtb2RlbCkNCmNvbmZpbnQobW9kZWwpDQpgYGANCg0KTWluZGV6dCDDoWJyw6F6b2xoYXRqdWsgaXMNCmBgYHtyfQ0KZ2djb2VmKG1vZGVsKQ0KYGBgDQoNCiMjY29ycnBsb3QNCg0KDQpLb3JyZWzDoWNpw7NzIG3DoXRyaXhvayDDoWJyw6F6b2zDoXNhDQpgYGB7cn0NCm10Y2FycyAlPiUgDQogIHNlbGVjdChtcGcsIGRpc3AsIGhwLCB3dCkgJT4lIA0KICBjb3IoKSAlPiUgIyBrb3JyZWzDoWNpw7NzIG3DoXRyaXgNCiAgY29ycnBsb3QoKQ0KYGBgDQoNCmBgYHtyfQ0KcF9tYXQgPC0gDQogIG10Y2FycyAlPiUgDQogIHNlbGVjdChtcGcsIGRpc3AsIGhwLCB3dCwgcXNlYykgJT4lIA0KICBjb3IubXRlc3QoKSAlPiUgLltbInAiXV0gIyBraW55ZXJqw7xrIGEga29ycmVsw6FjacOza2hveiB0YXJ0b3rDsyANCg0KbXRjYXJzICU+JSANCiAgc2VsZWN0KG1wZywgZGlzcCwgaHAsIHd0LCBxc2VjKSAlPiUgDQogIGNvcigpICU+JSAjIGtvcnJlbMOhY2nDs3MgbcOhdHJpeA0KICBjb3JycGxvdChwLm1hdCAgICAgICA9IHBfbWF0LCANCiAgICAgICAgICAgbWV0aG9kICAgICAgPSAic3F1YXJlIiwgDQogICAgICAgICAgIGFkZENvZWYuY29sID0gImxpZ2h0Z3JleSIsIA0KICAgICAgICAgICBtYXIgICAgICAgICA9IGMoMC4yLDEsMSwwLjUpLCANCiAgICAgICAgICAgaW5zaWcgICAgICAgPSAiYmxhbmsiKQ0KDQpgYGANCg0KQWtrb3IgaWdhesOhbiBoYXN6bm9zIGEgY29ycnBsb3QsIGhhIHNvayB2w6FsdG96w7Mga29ycmVsw6FjacOzasOhdCBzemVyZXRuw6luayBlZ3liZW4gw6F0dGVraW50ZW5pLg0KDQpQw6lsZMOhdWwgbsOpenrDvGsgbWVnIGVneSAyNSBrw6lyZMOpc2LFkWwgw6FsbMOzIEJpZyBGaXZlIHN6ZW3DqWx5aXPDqWd0ZXN6dCB0w6l0ZWxlaW5layBrb3JyZWzDoWNpw7NpdCENCg0KYGBge3J9DQpwc3ljaDo6YmZpICU+JQ0KICBzZWxlY3QoLShnZW5kZXI6YWdlKSkgJT4lIA0KICBjb3IodXNlID0gInAiKSAlPiUgDQogIGNvcnJwbG90KG1ldGhvZCAgICAgID0gInNxdWFyZSIsIA0KICAgICAgICAgICBtYXIgICAgICAgICA9IGMoMC4yLDEsMSwwLjUpKQ0KYGBgDQoNCg0KDQpbVG92w6FiYmkgYmXDoWxsw610w6FzaSBsZWhldMWRc8OpZ2VrIGEgY29ycnBsb3QtYmFuXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvY29ycnBsb3QvdmlnbmV0dGVzL2NvcnJwbG90LWludHJvLmh0bWwpDQoNCg0KIyBUw7ZiYiBwYW5lbGLFkWwgw6FsbMOzIMOhYnLDoWsgDQoNCmdyaWRBcnJhbmdlIGNzb21hZw0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZmlnLndpZHRoPTE1fQ0KcDEgPC0gZ2dwbG90KGRpYW1vbmRzKSArIA0KICBnZW9tX2ZyZXFwb2x5KGFlcyhwcmljZSksIGNvbD0iYmx1ZSIsYmlud2lkdGggPSAxMDAwKQ0KDQpwMiA8LSBnZ3Bsb3QoZGlhbW9uZHMpICsgDQogIGdlb21fcG9pbnQoYWVzKGNhcmF0LCBwcmljZSksIGFscGhhID0gMC4wMSwgY29sPSJibHVlIikNCg0KcDMgPC0gZ2dwbG90KGRpYW1vbmRzKSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMocHJpY2UpLCBmaWxsPSJibHVlIiwgYmlud2lkdGggPSAxMCkNCg0KZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIG5yb3cgPSAxKQ0KYGBgDQoNCsOBYnLDoWsgZWxyZW5kZXrDqXPDqW5layBmaW5vbWhhbmdvbMOhc2EgYSBsYXlvdXRfbWF0cml4IGFyZ3VtZW50dW1tYWwNCmBgYHtyLCBmaWcud2lkdGg9MTV9DQpncmlkLmFycmFuZ2UocDEsIHAyLCBwMywgDQogICAgICAgICAgICAgbGF5b3V0X21hdHJpeCA9IHJiaW5kKGMoMSwgMiwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoMywgMiwgMikpDQogICAgICAgICAgICAgKQ0KYGBgDQoNCltUb3bDoWJiaSBsZWhldMWRc8OpZ2VrIHTDtmJiIHBhbmVsYsWRbCDDoWxsw7Mgw6FicsOhayBzemVya2VzenTDqXPDqXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZWdnL3ZpZ25ldHRlcy9FY29zeXN0ZW0uaHRtbCkNCg0KDQojSW50ZXJha3TDrXYgw6FicsOhayBhIHBsb3RseS12ZWwNCg0KW0JldmV6ZXTDqXMgYSBwbG90bHkgaGFzem7DoWxhdMOhYmFdKGh0dHBzOi8vcGxvdGx5LWJvb2suY3BzaWV2ZXJ0Lm1lLykNCg0KTsOpenrDvG5rIG1lZyBlbHPFkW5layBlZ3kgdnVsa8OhbnQhDQpgYGB7cn0NCnBsb3RfbHkoeiA9IH52b2xjYW5vKQ0KYGBgDQoNCg0KYGBge3J9DQpwbG90X2x5KHogPSB+dm9sY2FubykgJT4lIGFkZF9zdXJmYWNlKCkNCmBgYA0KDQoNClRleGFzLWkgaW5nYXRsYW5waWFjaSBhZGF0b2sNCmBgYHtyfQ0KdHhob3VzaW5nDQpgYGANCg0KDQoNCkvDqXQgw7p0IGEgcGxvdGx5IG9iamVrdHVtb2sgbMOpdHJlaG96w6Fzw6FyYToNCg0KMSkgZ2dwbG90bHkoKTogZWd5IGdncGxvdCBvYmpla3R1bSDDoXRhbMOha8OtdMOhc2ENCjIpIHBsb3RfbHkoKToga8O2enZldGxlbsO8bCBheiBhZGF0b2sgbWVnYWTDoXNhDQoNCg0KIyNnZ3Bsb3RseSgpOiBlZ3kgZ2dwbG90IG9iamVrdHVtIMOhdGFsw6Frw610w6FzYQ0KDQpLw6lzesOtdHPDvG5rIGVneSBnZ3Bsb3QyIMOhYnLDoXQsIGFob2wgYXogaWTFkSBmw7xnZ3bDqW55w6liZW4gbXV0YXRqdWsgYSB2w6Fyb3NvbmvDqW50aSBtZWRpw6FuIGVsYWTDoXNpIMOhcmF0IQ0KYGBge3J9DQoocCA8LSBnZ3Bsb3QodHhob3VzaW5nLCBhZXMoZGF0ZSwgbWVkaWFuKSkgKw0KICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gY2l0eSksIGFscGhhID0gMC4yKSkNCmBgYA0KDQoNCkEgdG9vbHRpcCBhbGFwYsOzbCBtaW5kZW4gaW5mb3Jtw6FjacOzdCBtdXRhdCwgYW1pdCBheiBlc3p0w6l0aWthaSBrYXBjc29sw6FzbsOhbCAoYWVzKSBtZWdhZHR1bmsNCmBgYHtyfQ0KZ2dwbG90bHkocCkNCmBgYA0KDQpGZWzDvGwgaXMgw61yaGF0anVrLCBob2d5IG1pdCBrYXBqb24gbWVnIGEgdG9vbHRpcCAgDQpgYGB7cn0NCmdncGxvdGx5KHAsIHRvb2x0aXAgPSAiY2l0eSIpDQpgYGANCg0KIyNwbG90X2x5KCk6IGvDtnp2ZXRsZW7DvGwgYXogYWRhdG9rIG1lZ2Fkw6FzYQ0KDQpBZGF0b2sgbWFuaXB1bMOhbMOhc3JhIGEgZHBseXIgw6lzIGEgdGlkeXIgZsO8Z2d2w6lueWVpdCBoYXN6bsOhbGhhdGp1aw0KUGwuIGEgY3NvcG9ydG9zw610b3R0IGFkYXRva2F0ICLDqXJ0aSIgYSBwbG90bHkgDQooY3NvcG9ydG9zw610w6FzIG1pbmRlbiBlZ3llcyBzemludGrDqXJlIGxlc3ogbGVnYWzDoWJiIGVneSBncmFmaWthaSBlbGVtKQ0KDQpgYGB7cn0NCnR4IDwtIGdyb3VwX2J5KHR4aG91c2luZywgY2l0eSkNCmBgYA0KDQpMw6l0cmVob3p1bmsgZWd5IHBsb3RseSBvYmpla3R1bW90DQpgYGB7cn0NCnAgPC0gcGxvdF9seSh0eCwgeCA9IH5kYXRlLCB5ID0gfm1lZGlhbikNCmBgYA0KDQpwbG90bHlfZGF0YSgpIHZpc3N6YWFkamEgZWd5IHBsb3RseSBvYmpla3R1bWhveiB0YXJ0b3rDsyBhZGF0b2thdA0KYGBge3J9DQpwbG90bHlfZGF0YShwKSANCmBgYA0KYGBge3J9DQojIHbDoXJvc29ua8OpbnQgZmVscmFrdW5rIGVneS1lZ3kgdm9uYWxhdCBheiDDoWJyw6FyYSAodsOhcm9zIGNzb3BvcnRvc8OtdMOzIHbDoWx0b3rDsykNCnAgJT4lIA0KICBhZGRfbGluZXMoYWxwaGEgPSAwLjIsIG5hbWUgPSAiVGV4YW4gQ2l0aWVzIiwgaG92ZXJpbmZvID0gIm5vbmUiKSAlPiUgDQogICMgSG91c3RvbiBrYXAgZWd5IGvDvGzDtm4gdm9uYWxhdA0KICBhZGRfbGluZXMobmFtZSA9ICJIb3VzdG9uIiwgZGF0YSA9IGZpbHRlcih0eGhvdXNpbmcsIGNpdHkgPT0gIkhvdXN0b24iKSkNCmBgYA0KQSBwbG90bHkgY3NvbWFnYmFuIHZhbiBlZ3kgcmFrw6FzIGFkZF8qKCkgZsO8Z2d2w6lueQ0KDQpFemVrIMO2csO2a2xpayBhIHBsb3RfbHkoKSBow612w6Fza29yIG1lZ2hhdMOhcm96b3R0IGF0dHJpYsO6dHVtb2thdCAocGwuIG1lbHlpayB0ZW5nZWx5ZW4gbWkgbGVneWVuKQ0KDQrDiXMgw7Zyw7ZrbGlrIGEgcGxvdGx5IG9iamVrdHVtaG96IHRhcnRvesOzIGFkYXRva2F0LCBhbWl0IGZlbMO8bMOtcmhhdHVuayBhIGRhdGEgYXJndW1lbnR1bW7DoWwNCg0KR29uZG9saGF0dW5rIMO6Z3kgaXMgZXpla3JlIGEgZsO8Z2d2w6lueWVrcmUgbWludCBhIGdncGxvdDIgcsOpdGVnZWluZWsgZWd5IHbDoWx0b3phdMOhcmEgDQo=